package com.example.springboot_system.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    // 1、ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        factoryBean.setSecurityManager(defaultWebSecurityManager);
        factoryBean.setLoginUrl("/admin/login");
        /* 添加shiro的内置过滤器
        * 1、anon 无需认证就可访问
        * 2、authc 需要认证才可以访问
        * 3、user 需要实现“记住我”才能访问
        * 4、perms 拥有对某个资源的权限才可以访问
        * 5、role 拥有某个角色权限才能访问
        * */
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 静态资源无需认证
        filterChainDefinitionMap.put("/css/**", "anon"); // 静态资源匿名访问
        filterChainDefinitionMap.put("/images/*", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/sb-admin-2/**", "anon");
        filterChainDefinitionMap.put("/error/css/*", "anon");
        filterChainDefinitionMap.put("/error/images/*", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        filterChainDefinitionMap.put("/sb-admin-2/**", "anon");
        filterChainDefinitionMap.put("/xtiper/**", "anon");


        filterChainDefinitionMap.put("/admin/doLogin", "anon");
        filterChainDefinitionMap.put("/admin/doRegister", "anon");
        filterChainDefinitionMap.put("/logout", "logout"); // 用户退出
        filterChainDefinitionMap.put("/admin/getAllRole", "anon");
        filterChainDefinitionMap.put("/admin/sendEmail", "anon");
        filterChainDefinitionMap.put("/admin/checkEmail", "anon");

        filterChainDefinitionMap.put("/**", "authc"); // 其他路径均需要身份认证，一般位于最下面，优先级最低

        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        factoryBean.setLoginUrl("/admin/login"); //登录路径
        factoryBean.setSuccessUrl("/admin/toMain");// 主页

        return factoryBean;
    }

    // 2、DefaultWebSecurityManager
    @Bean(name = "getDefaultWebSecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getUserRealmBean") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    // 3、自定义的Realm
    @Bean(name = "getUserRealmBean")
    public UserRealm getUserRealmBean(){
        UserRealm realm = new UserRealm();
        return realm;
    }

    @Bean
    @DependsOn({ "lifecycleBeanPostProcessor" })
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启Shiro的注解
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}
